import { color } from "../../../core/color";
import { any } from "../../../core/logic";
import { Engine } from "../../../Engine";
import { Pass } from "../Pass";
import { Effect, EffectType } from "./Effect";
import { lggo_frag, lggo_frag_multisampled } from "./shaders/lggo_frag";
import { lggo_vert, lggo_vert_multisampled } from "./shaders/lggo_vert";
/**
 * Lift(提升,暗部调节)、Gain(增益,高光调节)、Gamma(伽玛,中间调调节)、Offset(灰度偏移,（偏移量）/Power（能量）/Slope（斜率）)
 * @class
 * @memberof w.effects
 */
class LGGO extends Effect {
  /**
   * @constructor
   * @param opts
   * @param opts.lift {String}【可选,缺省:"#ffffff"】提升,暗部调节参数。
   * @param opts.gain {String}【可选,缺省:"#ffffff"】增益,高光调节参数。
   * @param opts.gamma {String}【可选,缺省:"#ffffff"】伽玛,中间调调节参数。
   * @param opts.offset {String}【可选,缺省:"#000000"】灰度偏移调节参数。
   */
  constructor(opts = {}) {
    super(opts);
    this.type = EffectType.LGGO;
    this.sampler = Engine.instance.device.createSampler({
      magFilter: "linear", //nearest linear
      minFilter: "linear",
    });
    this.initBuffer();
    // this.initPipeLine();
    this.lift = any(opts.lift, "#ffffff");
    this.gamma = any(opts.gamma, "#ffffff");
    this.gain = any(opts.gain, "#ffffff");
    this.offset = any(opts.offset, "#000000");
  }
  get lift() {
    return this._lift;
  }
  set lift(v) {
    this._lift = v;
    let buffer = color.format(v, false);
    Engine.instance.queue.writeBuffer(this.liftBuffer, 0, buffer);
    buffer = null;
    this.update();
  }

  get gain() {
    return this._gain;
  }
  set gain(v) {
    this._gain = v;
    let buffer = color.format(v, false);
    Engine.instance.queue.writeBuffer(this.gainBuffer, 0, buffer);
    buffer = null;
    this.update();
  }

  get gamma() {
    return this._gamma;
  }
  set gamma(v) {
    this._gamma = v;
    let buffer = color.format(v, false);
    Engine.instance.queue.writeBuffer(this.gammaBuffer, 0, buffer);
    buffer = null;
    this.update();
  }

  get offset() {
    return this._offset;
  }
  set offset(v) {
    this._offset = v;
    let buffer = color.format(v, false);
    Engine.instance.queue.writeBuffer(this.offsetBuffer, 0, buffer);
    buffer = null;
    this.update();
  }
  initBuffer() {
    this.liftBuffer = Engine.instance.device.createBuffer({
      label: "lift",
      size: 12,
      usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
    });
    this.gainBuffer = Engine.instance.device.createBuffer({
      label: "gain",
      size: 12,
      usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
    });
    this.gammaBuffer = Engine.instance.device.createBuffer({
      label: "gamma",
      size: 12,
      usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
    });
    this.offsetBuffer = Engine.instance.device.createBuffer({
      label: "offset",
      size: 12,
      usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
    });
  }
  initPipeLine() {
    if (!this.pipeLine) {
      this.pipeLine = Engine.instance.device.createRenderPipeline({
        label: "LGGO Pipline",
        layout: `auto`,
        vertex: {
          module: Engine.instance.device.createShaderModule({
            code: lggo_vert,
          }),
          entryPoint: "main",
        },
        fragment: {
          module: Engine.instance.device.createShaderModule({
            code: lggo_frag,
          }),
          entryPoint: "main",
          targets: [
            {
              format: Engine.instance.format,
            },
          ],
        },
        primitive: {
          topology: "triangle-list",
          cullMode: "back",
          frontFace: "ccw",
        },
      });
    }

  }
  initBindGroup(texture) {
    if (this.group && this.group.id != texture.id) {
      this.group = null;
    }
    if (!this.group) {
      this.group = Engine.instance.device.createBindGroup({
        label: "LGGO group",
        layout: this.pipeLine.getBindGroupLayout(0),
        entries: [
          {
            binding: 0,
            resource: this.sampler,
          },
          {
            binding: 1,
            resource: texture.view,
          },
          {
            binding: 2,
            resource: {
              buffer: this.liftBuffer,
              size: 12,
            },
          },
          {
            binding: 3,
            resource: {
              buffer: this.gainBuffer,
              size: 12,
            },
          },
          {
            binding: 4,
            resource: {
              buffer: this.gammaBuffer,
              size: 12,
            },
          },
          {
            binding: 5,
            resource: {
              buffer: this.offsetBuffer,
              size: 12,
            },
          },
        ],
      });
      this.group.id = texture.id;
    }
    return this.group;
  }
  onRender(commandEncoder) {
    //执行帧渲染
    const pass = super.onRender(commandEncoder);
    this.initPipeLine()
    const texture = Pass.instance().readAttach;
    const renderPass = commandEncoder.beginRenderPass(pass);
    renderPass.setPipeline(this.pipeLine);
    let bindGroup = this.initBindGroup(texture);
    // set uniformGroup
    renderPass.setBindGroup(0, bindGroup);
    renderPass.draw(3);
    renderPass.end();
  }
  getDescript() {
    if (this._descript) {
      if (
        this._descript.size[0] !== Engine.instance.size[0] ||
        this._descript.size[1] !== Engine.instance.size[1]
      ) {
        this._descript = null;
      } else {
        this._descript.colorAttachments[0].view =
          Pass.instance().writeAttach.view;
      }
    }
    if (!this._descript) {
      this._descript = {
        colorAttachments: [
          {
            view: Pass.instance().writeAttach.view,
            loadOp: "clear",
            clearValue: {
              r: 1.0,
              g: 1.0,
              b: 1.0,
              a: 1.0,
            },
            storeOp: "store",
          },
        ],
      };
      this._descript.size = Engine.instance.size;
    }
    return this._descript;
  }
}
export { LGGO };
